﻿#ifndef MUDUO_BASE_SIGNALSLOT_H
#define MUDUO_BASE_SIGNALSLOT_H

#include <functional>
#include <memory>
#include "NonCopyable.h"
#include "HongMutex.h"


#include <vector>



namespace muduo
{

namespace detail
{

template<typename Callback>
struct SlotImpl;

template<typename Callback>
struct SignalImpl : NonCopyable
{
    typedef std::vector<std::weak_ptr<SlotImpl<Callback> > > SlotList;

    SignalImpl()
        : slots_(new SlotList) //指向链表的指针
    {
    }

    void copyOnWrite()
    {
        mutex_.Unlock();

        if (!slots_.unique())
        {
            /// SignalImpl禁止拷贝，slots_应该始终是唯一占用的
            /// 下面的代码应当不会被执行
            std::cout<<"tc debug 505 : "<<slots_.use_count()<<std::endl;
            slots_.reset(new SlotList(*slots_));
        }
        assert(slots_.unique());
    }

    void clean()
    {
        HONG_CS_LOCK(mutex_);
        copyOnWrite();
        SlotList& list(*slots_);
        typename SlotList::iterator it(list.begin());
        while (it != list.end())
        {
            if (it->expired())
            {
                it = list.erase(it);
            }
            else
            {
                ++it;
            }
        }
    }

    Hong::Mutex mutex_;
    std::shared_ptr<SlotList> slots_;
};

template<typename Callback>
struct SlotImpl : NonCopyable
{
    //信号的发送者
    typedef SignalImpl<Callback> Data;
    SlotImpl(const std::shared_ptr<Data>& data, Callback&& cb)
        : data_(data), cb_(cb), tie_(), tied_(false)
    {
    }

    SlotImpl(const std::shared_ptr<Data>& data, Callback&& cb,
             const std::shared_ptr<void>& tie)
        : data_(data), cb_(cb), tie_(tie), tied_(true)
    {
    }

    ~SlotImpl()
    {
        std::cout<<"tc debug 510 : slot impl obj release"<<std::endl;
        std::shared_ptr<Data> data(data_.lock());
        if (data)
        {
            //清除发送者内部注册的槽函数
            data->clean();
        }
    }

    std::weak_ptr<Data> data_;
    Callback cb_;
    std::weak_ptr<void> tie_;
    bool tied_;
};

}

/// This is the handle for a slot
///
/// The slot will remain connected to the signal fot the life time of the
/// returned Slot object (and its copies).
typedef std::shared_ptr<void> Slot;

template<typename Signature>
class Signal;

template <typename RET, typename... ARGS>
class Signal<RET(ARGS...)> : NonCopyable
{
                                 public:
                                 typedef std::function<void (ARGS...)> Callback;
typedef detail::SignalImpl<Callback> SignalImpl;
typedef detail::SlotImpl<Callback> SlotImpl;

Signal()
    : impl_(new SignalImpl)
{
}

~Signal()
{
}
/**
  *@brief 本信号，能够连接n个槽
*/
Slot connect(Callback&& func)
{
    std::shared_ptr<SlotImpl> slotImpl(
                new SlotImpl(impl_/*发送者*/, std::forward<Callback>(func)));
    add(slotImpl);
    return slotImpl;
}

Slot connect(Callback&& func, const std::shared_ptr<void>& tie)
{
    std::shared_ptr<SlotImpl> slotImpl(new SlotImpl(impl_, func, tie));
    add(slotImpl);
    return slotImpl;
}

void call(ARGS&&... args)
{
    SignalImpl& impl(*impl_);
    std::shared_ptr<typename SignalImpl::SlotList> slots;
    {
        HONG_CS_LOCK(impl.mutex_);
        slots = impl.slots_;
    }
    typename SignalImpl::SlotList& s(*slots);
    for (typename SignalImpl::SlotList::const_iterator it = s.begin(); it != s.end(); ++it)
    {
        //该槽在的智能指针，在外部被置为空，此时没有任何智能指针，指向该槽
        //对象已被释放，同时注销了
        std::shared_ptr<SlotImpl> slotImpl = it->lock();
        if (slotImpl)
        {
            std::shared_ptr<void> guard;
            if (slotImpl->tied_)
            {
                guard = slotImpl->tie_.lock();
                if (guard)
                {
                    slotImpl->cb_(args...);
                }
            }
            else
            {
                slotImpl->cb_(args...);
            }
        }
    }
}

private:

void add(const std::shared_ptr<SlotImpl>& slot)
{
    //声明一个SignalImpl对象的引用，并初始化
    SignalImpl& impl(*impl_);
    {
        HONG_CS_LOCK(impl.mutex_);
        impl.copyOnWrite();
        impl.slots_->push_back(slot);
    }
}

const std::shared_ptr<SignalImpl> impl_;
};

}

#endif // MUDUO_BASE_SIGNALSLOT_H
